package ar.edu.itba.tp1.gps.board;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import ar.edu.itba.tp1.gps.GPSRun;
import ar.edu.itba.tp1.gps.api.GPSState;

public class ArithmeticsRestrictions {

	private Bucket[][] cells;
	private Set<Bucket> buckets;
	
	public ArithmeticsRestrictions() {
		cells = new Bucket[GPSRun.n][GPSRun.n];
		buckets = new HashSet<Bucket>();
	}
	
	public void addBucket(Bucket bucket, Coordinate coordinate) {
		Integer x = coordinate.getX();
		Integer y = coordinate.getY();
		if (bucket != null && x >= 0 && x < GPSRun.n && y >= 0 && y < GPSRun.n) {
			cells[x][y] = bucket;
			buckets.add(bucket);
		}
	}
	
	public boolean checkRestriction(GPSState state, Integer value, Coordinate coordinate) {
		Integer i = coordinate.getX();
		Integer j = coordinate.getY();
		Integer[][] matrixValues = state.getValues();
		Bucket bucket = cells[i][j];
		List<Coordinate> groupCells = bucket.getGroupCells();
		List<Integer> cellValues = new LinkedList<Integer>();
		for (int k = 0; k < groupCells.size(); k++) {
			Integer cellRowIndex = groupCells.get(k).getX();
			Integer cellColIndex = groupCells.get(k).getY();
			Integer v = matrixValues[cellRowIndex][cellColIndex];
			if (v != null) {
				cellValues.add(v);
			}
		}
		cellValues.add(value);
		int result;
		switch (bucket.getOperator()) {
			case ADD:
				result = addOperation(cellValues);
				break;
			default:
				result = prodOperation(cellValues);
				break;
		}
		if (cellValues.size() == groupCells.size()) {
			return (result == bucket.getGroupResult());
		} else {
			return (result < bucket.getGroupResult());
		}
	}

	public List<Bucket> getBoardRestictions() {
		return new LinkedList<Bucket>(buckets);
	}

	private Integer prodOperation(List<Integer> cellValues) {
		Integer prod = 1;
		for (Integer cellValue: cellValues) {
			prod *= cellValue;
		}
		return prod;
	}

	private Integer addOperation(List<Integer> cellValues) {
		Integer sum = 0;
		for (Integer cellValue: cellValues) {
			sum += cellValue;
		}
		return sum;
	}

}
